/**
 * Used for insert command.
 * @param {Object} params
 */
NG.command.GEOMETRY = function(params) {
	this.category = params.category;
	this.MultiGeometry = {
		geometryMember: {
		},	
		
		/**
		 * Must be implemented below according to category. 
		 * @returns {String} coordinates
		 */
		getCoordinates: function (){
			return "";
		}
	};
	if (this.category.isGeoPolygon()){
		this.MultiGeometry.geometryMember['Polygon'] = {
			outerBoundaryIs: {
				LinearRing: {
					coordinates: Ext.isEmpty(params.coordinates) ? '' : params.coordinates
				}
			}				
		};
		this.MultiGeometry.getCoordinates = function (){
			return this.geometryMember.Polygon.outerBoundaryIs.LinearRing.coordinates;			
		};
	} else if (this.category.isGeoPath()){
		this.MultiGeometry.geometryMember['LineString'] = {
			coordinates: Ext.isEmpty(params.coordinates) ? '' : params.coordinates
		};	
		this.MultiGeometry.getCoordinates = function (){
			return this.geometryMember.LineString.coordinates;			
		};
	} else if (this.category.isGeoPoint()){
		this.MultiGeometry.geometryMember['Point'] = {
			coordinates: Ext.isEmpty(params.coordinates) ? '' : params.coordinates
		};		
		this.MultiGeometry.getCoordinates = function (){
			return this.geometryMember.Point.coordinates;			
		};
	}
	
	/**
	 * 
	 * @returns {String} coordinates
	 */
	this.getCoordinates = function (){
		return this.MultiGeometry.getCoordinates();
	};

	/**
	 * Appends xml representation of this to xml
	 * 
	 * @param {XMLWriter} XML
	 * @returns xml string of this if XML is empty else full xml string
	 */
	this.appendXML = function (XML){
		if (Ext.isEmpty(XML)) XML = new XMLWriter();
    	XML.BeginNode("GEOMETRY");
    	XML.BeginNode("MultiGeometry");
    	XML.BeginNode("geometryMember");
    	if (this.category.isGeoPolygon()) {
        	XML.BeginNode("Polygon");
        	XML.BeginNode("outerBoundaryIs");
        	XML.BeginNode("LinearRing");
        	XML.Node("coordinates", this.getCoordinates());
        	XML.EndNode();
        	XML.EndNode();
        	XML.EndNode();    		
    	} else if (this.category.isGeoPath()) {
        	XML.BeginNode("LineString");
        	XML.Node("coordinates", this.getCoordinates());        	
        	XML.EndNode();    		
    	} else if (this.category.isGeoPoint()) {
        	XML.BeginNode("Point");
        	XML.Node("coordinates", this.getCoordinates());        	
        	XML.EndNode();
    	}
    	XML.EndNode();
    	XML.EndNode();
    	XML.EndNode();
    	XML.Close();
    	return XML.ToString();
	};
};

/**
 * Adds filter xml string to XML as '<ogc:Filter><MAHALLE_KODU>8</MAHALLE_KODU> </ogc:Filter>'
 */
NG.command.Filter = function(params) {
	params = params || {
		tagName: '',
		value: ''
	};
	
	this.tagName = params.tagName;
	this.value = params.value;
	
	this.appendXML = function (XML){
		if (Ext.isEmpty(XML)) XML = new XMLWriter();
    	XML.BeginNode("ogc:Filter");
    		XML.Node(this.tagName, this.value);
    	XML.EndNode();
    	XML.Close();
    	return XML.ToString();
	};	
};


/**
 * 
 * @class NG.command.PutInfoEx
 * @extends Ext.util.Observable
 */
NG.command.PutInfoEx = Ext.extend(NG.command.Request, {
	
	/**
	 * This property must be defined as config options. Default value is null.
	 * @cfg {String} dmlType
	 */
	dmlType: null, //insert, update, delete
	
	/**
	 * For updating and inserting, this property handles {field name, value} pairs are injected to xml data.
	 * If delete dml type is indicated, this property has no effect. 
	 * @cfg {HashMap} modifiedFields  
	 */
	modifiedFields: null, 
	
	/**
	 * This property must be defined as config options or infoDetail config options must be defined. 
	 * Available values are 'insert', 'delete' and 'update'.
	 * Default value is null.
	 * @cfg {String} typeName
	 */
	typeName: null, //etc. MAHALLE.EGITIM.MAHALLE
	
	/**
	 * 
	 * @cfg {NG.models.InfoDetail}
	 */
	infoDetail: null, //NG.models.InfoDetail
	
	infoMapForInsert: null,
	
	geometry: null,
	
	/**
	 * @private
	 * @param {object} config
	 */
	constructor: function(config){
		config = config || {};
		config.serviceName = XSN_NCDD_PUTINFOEX;
		NG.command.PutInfoEx.superclass.constructor.call(this, config);
		if (Ext.isEmpty(this.typeName) && config.infoDetail && config.infoDetail.getFeatureName)
			this.typeName = config.infoDetail.getFeatureName();
	},

	/**
	 * @private 
	 * @param XML
	 */
	addModifiedFields: function (XML) {
		if (this.modifiedFields) {
	    	var modifiedFieldsMap = this.modifiedFields;
	    	var fieldNameArray = modifiedFieldsMap.getKeys();
	    	for ( var i = 0; i < fieldNameArray.length; i++) {
	    		var fieldName = fieldNameArray[i];
	    		var value = modifiedFieldsMap.get(fieldName);
	    		if (this.dmlType === "update") {
		    		XML.BeginNode("wfs:Property");
	    			XML.Node("wfs:Name", fieldName);
	    			XML.Node("wfs:Value", value);
	    			XML.EndNode();		    			    			
	    		}
	    		else if (this.dmlType === "insert") {
		    		XML.Node(fieldName, value);
				}
			}
		}
	},
	
	/**
	 * The <b>geometry</b> property must be set.
	 * @return {String} data xml string of the server command.
	 */
	getDataXML: function(){
		
    	var XML = new XMLWriter();
    	XML.BeginNode("wfs:Transaction");
    	XML.Attrib("xmlns:wfs", "http://www.opengis.net/wfs");
    	XML.Attrib("xmlns:gml", "http://www.opengis.net/gml");
    	XML.Attrib("xmlns:ogc", "http://www.opengis.net/ogc");
    	if (this.dmlType === "insert") {
    		XML.BeginNode("wfs:Insert");
    		XML.BeginNode(this.typeName);
    		this.addModifiedFields(XML);
        	this.geometry.appendXML(XML);
    	} else if (this.dmlType === "update") {
    		XML.BeginNode("wfs:Update");
    		XML.Attrib("typeName", this.typeName);
    		this.addModifiedFields(XML);
    		var fieldName = this.infoDetail.getPrimaryKeyFieldName(); 
    		this.addFilter(fieldName, this.infoDetail.getValueOfProperty(fieldName), XML);
    	} else if (this.dmlType === "delete") {
    		XML.BeginNode("wfs:Delete");
    		XML.Attrib("typeName", this.typeName);
    		var fieldName = this.infoDetail.getPrimaryKeyFieldName(); 
    		this.addFilter(fieldName, this.infoDetail.getValueOfProperty(fieldName), XML);
    	}
		
    	XML.Close();
    	return XML.ToString();
	},
	
	/**
	 * @private
	 */
	addFilter: function (tagName, value, XML) {
		var filter = new NG.command.Filter({
			tagName: tagName,
			value: value
		});
		filter.appendXML (XML);
	},
	
	validate: function () {
		var errorStr = "";
		if(Ext.isEmpty(this.typeName)) {
			errorStr += "typeName(FAD name) property must be defined";
		}	
		if (!(this.dmlType == "update" || this.dmlType == "insert" || this.dmlType == "delete")) {
			errorStr += "\ndmlType property must be defined or must be one of these (update, insert, delete)";
		} 
		this.errorStr = errorStr;
		return Ext.isEmpty(errorStr);
	},
	
	/**
	 * 
	 * @return {String}
	 */
	getIsValidCacheKey: function (){
		return this.getWorkspaceName() + "-" + this.getRunXmlUrl() + "-" + this.getIsValidUrl();
	},

	getResponse: function(xmlData){
		return new NG.response.PutInfoEx({
			command: this,
			xmlData: xmlData
		});			
	}
});